Guild icon
Project Sekai
🔒 UIUCTF 2023 / ✅-rev-fast-calculator
Avatar
Fast Calculator - 500 points
Category: Rev Description: Check out our new super fast calculator! This challenge is sponsored by Battelle. Files:Tags: medium
Sutx pinned a message to this channel. 06/30/2023 5:15 PM
Avatar
@Violin wants to collaborate 🤝
Avatar
@IceCreamMan wants to collaborate 🤝
Avatar
@kanon wants to collaborate 🤝
Avatar
@IceCreamMan any lead?
Avatar
@Utaha wants to collaborate 🤝
19:44
@Rench wants to collaborate 🤝
Avatar
this part looks like regular a op b
19:50
didnt see anything special
19:50
while ( v76 != 8573.8567 )
19:50
so result needs to be this?
Avatar
floating point comparison 💀
Avatar
Enter your operation: 85738567 / 10000 Result: 8573.856700 Correct! Attempting to decrypt the flag... I calculated 368 operations, tested each result in the gauntlet, and flipped 119 bits in the encrypted flag! Here is your decrypted flag: uiuctf{This is a fake flag. You are too fast!}
19:53
so prob need to fit some of their constraints
19:53
looks like maths problem
19:53
let me check
19:54
im not sure how it decrypts to the fake flag
19:57
Enter your operation: 2.2 ^ 21.2 Result: 18170247.101873 lol
Avatar
still dont know the goal
20:22
oh maybe need bit flip count == operations? (edited)
20:23
bit flip happens when _BOOL8 __fastcall gauntlet(double a1) { return (unsigned __int8)isNegative(a1) || (unsigned __int8)isNotNumber(a1) || (unsigned __int8)isInfinity(a1); }
Avatar
Avatar
sahuang
oh maybe need bit flip count == operations? (edited)
actually i think goal is to flip 0 bits
20:24
__int64 v52[1104]; we need the value of this
20:25
1104/3 is 368
20:25
so it basically groups this array by 3's
20:25
j_memcpy(v52, "%", sizeof(v52)); seems to fill it with %
Avatar
IceCreamMan 06/30/2023 8:26 PM
starting on it
Avatar
for ( i = 0; i < 368; ++i ) { v30 = calculate(v52[3 * i], v52[3 * i + 1], v52[3 * i + 2]); if (gauntlet(v30) ) { // flip bit } } They had this check in the end (edited)
20:27
and i think we need to not have flips
20:28
but v52 seems to be size 1104 with all %'s. so idk why it can have calculations done
Avatar
@IceCreamMan are you able to breakpoint and see what are the values here at v30 = calculate((__int64)v34, v26, i, v27, v28, v29, v52[3 * i], v52[3 * i + 1], v52[3 * i + 2]); for v52?
20:42
kinda confused
20:42
it isnt modified in code anywhere and initialzied with all %
Avatar
IceCreamMan 06/30/2023 8:43 PM
the one in the for loop?
Avatar
yeah i think so
20:45
also flag len 46
Avatar
IceCreamMan 06/30/2023 8:45 PM
the for loop seems bruteforce-able
Avatar
Avatar
sahuang
@IceCreamMan are you able to breakpoint and see what are the values here at v30 = calculate((__int64)v34, v26, i, v27, v28, v29, v52[3 * i], v52[3 * i + 1], v52[3 * i + 2]); for v52?
IceCreamMan 06/30/2023 8:45 PM
they dont seem to use the result of the calculation here
Avatar
seems so
20:46
maybe need patch if ( gauntlet(v30) ) ? (edited)
Avatar
IceCreamMan 06/30/2023 8:46 PM
other than gauntlet(result) -> which we can just hook to return 0/1 (edited)
20:46
for ( i = 0; i < (int)val_368; ++i ) { v47 = calculate((unsigned int)&v54, (_DWORD)v43, i, v44, v45, v46, v73[3 * i], v73[3 * i + 1], v73[3 * i + 2]); if ( (unsigned __int8)gauntlet(v47) ) { v63 = i / 8; v64 = i % 8; LODWORD(v43) = 1 << (7 - i % 8); v44 = (unsigned int)v43 ^ *((unsigned __int8 *)flag_shit + i / 8); *((_BYTE *)flag_shit + v63) ^= 1 << (7 - i % 8); ++v59; } }
Avatar
we need it return 0 i think
20:46
so its not flipped
Avatar
IceCreamMan 06/30/2023 8:46 PM
v44 doesnt matter too
Avatar
yeah it basically flips i-th bit in flag (edited)
20:47
i is 0-368
20:48
well it seems 119 bits are flipped by them with this algo
20:48
which gives uiuctf{This is a fake flag. You are too fast!}
20:48
but idk how 119 comes from
Avatar
IceCreamMan 06/30/2023 8:49 PM
oops (edited)
20:50
0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0
20:50
This is one run producing fake flag
20:51
I will try do in python, and try bit flipping
Avatar
how does that produce fake flag, hmm
20:52
didnt convert to flag
20:52
while ( v46 != 8573.8567 ) so is this not even used
20:53
85738567 is UIUC lol, prob trolling?
Avatar
IceCreamMan 06/30/2023 8:53 PM
if i used 8573.8567 + 0, pwndbg> x/50bx 0x7fffffffaf70 0x7fffffffaf70: 0x4b 0xc3 0xe1 0x01 0x00 0xb9 0xee 0x10 0x7fffffffaf78: 0xee 0x4b 0xf0 0xa4 0x78 0x21 0x38 0xcb 0x7fffffffaf80: 0xea 0x2a 0x21 0x6b 0xce 0x83 0x46 0xe8 0x7fffffffaf88: 0x41 0xa7 0x8c 0x2c 0x09 0xcf 0xf5 0xa0 0x7fffffffaf90: 0xa1 0x72 0x27 0x08 0x60 0x28 0xa9 0x20 0x7fffffffaf98: 0x66 0xb3 0xab 0x35 0xa4 0xe9 0x00 0x00
20:53
This array is bit flip with the above 1 and 0s array
Avatar
Avatar
IceCreamMan
if i used 8573.8567 + 0, pwndbg> x/50bx 0x7fffffffaf70 0x7fffffffaf70: 0x4b 0xc3 0xe1 0x01 0x00 0xb9 0xee 0x10 0x7fffffffaf78: 0xee 0x4b 0xf0 0xa4 0x78 0x21 0x38 0xcb 0x7fffffffaf80: 0xea 0x2a 0x21 0x6b 0xce 0x83 0x46 0xe8 0x7fffffffaf88: 0x41 0xa7 0x8c 0x2c 0x09 0xcf 0xf5 0xa0 0x7fffffffaf90: 0xa1 0x72 0x27 0x08 0x60 0x28 0xa9 0x20 0x7fffffffaf98: 0x66 0xb3 0xab 0x35 0xa4 0xe9 0x00 0x00
how about another ops
Avatar
IceCreamMan 06/30/2023 8:53 PM
let me try other operation to see if the below array change
Avatar
yeah like 8573.8567 ^ 1 and 85738567 / 10000
20:54
i think same
20:54
cuz this operation isnt even referenced later
Avatar
IceCreamMan 06/30/2023 8:54 PM
For 8573.8567 ^ 1 pwndbg> x/50bx $rdx 0x7fffffffaf70: 0x4b 0xc3 0xe1 0x01 0x00 0xb9 0xee 0x10 0x7fffffffaf78: 0xee 0x4b 0xf0 0xa4 0x78 0x21 0x38 0xcb 0x7fffffffaf80: 0xea 0x2a 0x21 0x6b 0xce 0x83 0x46 0xe8 0x7fffffffaf88: 0x41 0xa7 0x8c 0x2c 0x09 0xcf 0xf5 0xa0 0x7fffffffaf90: 0xa1 0x72 0x27 0x08 0x60 0x28 0xa9 0x20 0x7fffffffaf98: 0x66 0xb3 0xab 0x35 0xa4 0xe9 0x00 0x00
20:54
seems like no change
20:55
let me try a bit more
20:56
Enter your operation: 1714.77134 * 5 pwndbg> x/50bx $rdx 0x7fffffffaf70: 0x4b 0xc3 0xe1 0x01 0x00 0xb9 0xee 0x10 0x7fffffffaf78: 0xee 0x4b 0xf0 0xa4 0x78 0x21 0x38 0xcb 0x7fffffffaf80: 0xea 0x2a 0x21 0x6b 0xce 0x83 0x46 0xe8 0x7fffffffaf88: 0x41 0xa7 0x8c 0x2c 0x09 0xcf 0xf5 0xa0 0x7fffffffaf90: 0xa1 0x72 0x27 0x08 0x60 0x28 0xa9 0x20 0x7fffffffaf98: 0x66 0xb3 0xab 0x35 0xa4 0xe9 0x00 0x00
20:56
seems like no change?
Avatar
yeah its not used
20:56
and final flag is the same fake flag
Avatar
IceCreamMan 06/30/2023 8:56 PM
yeah
20:56
somehow lol
20:57
the brute force should be possible (edited)
Avatar
how do you brute force?
Avatar
Avatar
IceCreamMan
0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0
IceCreamMan 06/30/2023 8:57 PM
sets of 8 here are for one char
20:57
i will flip them and see if its a ascii char (edited)
Avatar
do you know how its converted to fake flag?
20:58
didnt get whats that array for\
Avatar
IceCreamMan 06/30/2023 8:58 PM
when its 1, it will enter the if branch
Avatar
yeah
Avatar
IceCreamMan 06/30/2023 8:58 PM
*((_BYTE *)flag_shit + v63) ^= 1 << (7 - i % 8); and this happens i guess?
20:59
is that bit array after the 119 shifts or before?
Avatar
Avatar
IceCreamMan
0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0
IceCreamMan 06/30/2023 8:59 PM
this the result of gauntlet
Avatar
oh ok
21:00
0, 0, 1, 1, 1, 1, 1, 0 here it shifts 5 times at the beginning but printed flag is still u?
21:00
weird
Avatar
IceCreamMan 06/30/2023 9:05 PM
import IPython bit_arr = [0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0] original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9] for i in range(0,len(bit_arr)): idx = bit_arr[i] if (idx == 1): v63 = int(i / 8) original_flag[v63] ^= 1 << (7 - i % 8); print(original_flag) string = ''.join(chr(num) for num in original_flag) print(string) IPython.embed()
Avatar
IceCreamMan 06/30/2023 9:06 PM
so the first 7 set represents UTFCTF{ is definitely right
21:07
can just start from the 8 set, 8 * 8 (edited)
Avatar
oh i see
21:08
but do we know how many bits need to be flipped?
Avatar
IceCreamMan 06/30/2023 9:09 PM
nope
Avatar
then it can be anything?
21:12
🤣
Avatar
IceCreamMan 06/30/2023 9:12 PM
i dont think every permutation will return readable chars
21:12
i am banging on this assumption
21:12
🤣
Avatar
Avatar
IceCreamMan
i dont think every permutation will return readable chars
IceCreamMan 06/30/2023 9:15 PM
oh no there are multiple readable chars
21:19
hmm means the above operation does matter, although i dont see where yet
Avatar
Avatar
IceCreamMan
import IPython bit_arr = [0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0] original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9] for i in range(0,len(bit_arr)): idx = bit_arr[i] if (idx == 1): v63 = int(i / 8) original_flag[v63] ^= 1 << (7 - i % 8); print(original_flag) string = ''.join(chr(num) for num in original_flag) print(string) IPython.embed()
i think some info is missing, like what/how many bits to flip? otherwise seems hard to get flag
21:43
there's noway to solve without knowing how many bits should be flipped
Avatar
IceCreamMan 06/30/2023 9:52 PM
yeah thinking about it
Avatar
puts("\nCorrect! Attempting to decrypt the flag...", &v65, v23, v24); v68 = v61 - 1LL; v41 = 16 * ((v61 + 15LL) / 0x10uLL); while ( &v54 != (__int64 *)((char *)&v54 - (v41 & 0xFFFFFFFFFFFFF000LL)) ) ; v42 = alloca(v41 & 0xFFF); if ( (v41 & 0xFFF) != 0 ) *(__int64 *)((char *)&v54 + (v41 & 0xFFF) - 8) = *(__int64 *)((char *)&v54 + (v41 & 0xFFF) - 8); v69 = &v54; v43 = v74; j_memcpy(&v54, v74, v61); v59 = 0; for ( i = 0; i < (int)v62; ++i ) What is middle part doing?
Avatar
Avatar
IceCreamMan
for ( i = 0; i < (int)val_368; ++i ) { v47 = calculate((unsigned int)&v54, (_DWORD)v43, i, v44, v45, v46, v73[3 * i], v73[3 * i + 1], v73[3 * i + 2]); if ( (unsigned __int8)gauntlet(v47) ) { v63 = i / 8; v64 = i % 8; LODWORD(v43) = 1 << (7 - i % 8); v44 = (unsigned int)v43 ^ *((unsigned __int8 *)flag_shit + i / 8); *((_BYTE *)flag_shit + v63) ^= 1 << (7 - i % 8); ++v59; } }
there is a big byte array here v73. IDA decompile it very bad, v73 is what stores the number input and operation
Avatar
Avatar
sahuang
puts("\nCorrect! Attempting to decrypt the flag...", &v65, v23, v24); v68 = v61 - 1LL; v41 = 16 * ((v61 + 15LL) / 0x10uLL); while ( &v54 != (__int64 *)((char *)&v54 - (v41 & 0xFFFFFFFFFFFFF000LL)) ) ; v42 = alloca(v41 & 0xFFF); if ( (v41 & 0xFFF) != 0 ) *(__int64 *)((char *)&v54 + (v41 & 0xFFF) - 8) = *(__int64 *)((char *)&v54 + (v41 & 0xFFF) - 8); v69 = &v54; v43 = v74; j_memcpy(&v54, v74, v61); v59 = 0; for ( i = 0; i < (int)v62; ++i ) What is middle part doing?
no idea yet
Avatar
v71 = 0x10EEB90001E1C34BLL; // these are the encoded bytes v72 = 0xCB382178A4F04BEELL; v73 = 0xE84683CE6B212AEALL; v74 = 0xA0F5CF092C8CA741LL; v75 = 0x20A92860082772A1LL; v76 = 900445030; v77 = 0xE9A4; These make up the encoded bytes that goes through the for loop (edited)
Avatar
will try a bit before sleep, last rev is too evil so this one to go
Avatar
Avatar
IceCreamMan
v71 = 0x10EEB90001E1C34BLL; // these are the encoded bytes v72 = 0xCB382178A4F04BEELL; v73 = 0xE84683CE6B212AEALL; v74 = 0xA0F5CF092C8CA741LL; v75 = 0x20A92860082772A1LL; v76 = 900445030; v77 = 0xE9A4; These make up the encoded bytes that goes through the for loop (edited)
yeah
Avatar
hmm i realise the results of gauntlet can change i am wrong (edited)
Avatar
depend on the number of times we run the operation ignore (edited)
23:12
what operation
Avatar
any operation
Avatar
like the arithmetics before exiting loop?
Avatar
if you do 1 + 1 and then do something correct
Avatar
like if we run 2 times
23:12
ah
23:12
damn
Avatar
or just submitting something correct repeatedly will yield different results of gaunlet (edited)
23:12
but the final result is always the same, as in the fake flag is shown (edited)
Avatar
but if gaunlet is changed then why final result is the same
Avatar
uiuctf{This is a fake flag. You are too fast!} -> idk what too fast means
Avatar
maybe you need a lot more operations before getting to correct one?
Avatar
Avatar
IceCreamMan
v71 = 0x10EEB90001E1C34BLL; // these are the encoded bytes v72 = 0xCB382178A4F04BEELL; v73 = 0xE84683CE6B212AEALL; v74 = 0xA0F5CF092C8CA741LL; v75 = 0x20A92860082772A1LL; v76 = 900445030; v77 = 0xE9A4; These make up the encoded bytes that goes through the for loop (edited)
this change too i believe.. let me check more
Avatar
Avatar
sahuang
but if gaunlet is changed then why final result is the same
yeah.. i am puzzled, need to check more
23:17
ohhh
23:17
let me try something
Avatar
i checked with admin they said it needs some guessing
Avatar
const_45 = const_46 - 1LL; const_num = 16 * ((const_46 + 15LL) / 0x10uLL);
23:18
this thing changes every time we decrypt
Avatar
oh wait
Avatar
oh no it doesnt
23:21
-.- i see wrong
Avatar
there is a while (1) at the outest loop, idk if that matters
23:22
seems unrelated
23:22
too bad at guessing
Avatar
hmm
23:23
does the flip 119 bits help in anyway?
Avatar
Avatar
sahuang
but do we know how many bits need to be flipped?
this
Avatar
>>> bin(ord(" "))[2:].zfill(8) '00100000' >>> bin(ord("_"))[2:].zfill(8) '01011111' btw kinda wondering if the should be replaced by _, looking at this seems all bits except upper bit are shifted
23:27
but it doesnt apply to other scenarios
23:27
so maybe not
23:28
v62 = 368 this prob is useful
23:28
They said "I calculated 368 operations, tested each result in the gauntlet"
Avatar
@Lior 🟣🐑 wants to collaborate 🤝
Avatar
need help on this chal, guessy af
01:17
above chat is a good read
Avatar
@joezid wants to collaborate 🤝
Avatar
Lior 🟣🐑 07/01/2023 1:31 AM
I think I have a spare hour
01:32
taking a look into it
Avatar
IceCreamMan 07/01/2023 1:36 AM
i have no idea how to solve it
01:36
...
Avatar
Lior 🟣🐑 07/01/2023 1:36 AM
wanna hop on vc?
01:36
tell me what you guys did so far
Avatar
IceCreamMan 07/01/2023 1:37 AM
i have no earphones
01:37
i can quickly type here
Avatar
Lior 🟣🐑 07/01/2023 1:37 AM
sure
01:37
(I can read history but I'd appreciate a short recap)
Avatar
IceCreamMan 07/01/2023 1:37 AM
1. The decompiled code just checks if the sum of an operation is 8573.8567 2. however the user inputs does not seem to be used at all
Avatar
Lior 🟣🐑 07/01/2023 1:37 AM
especially if some progress wasn't typed here
Avatar
IceCreamMan 07/01/2023 1:39 AM
3. The most important parts are here: for ( i = 0; i < (int)val_368; ++i ) { v44 = calculate( *(_QWORD *)&big_byte_array[0x18 * i - 0x30],// these are arguments on the stack *(double *)&big_byte_array[0x18 * i - 0x28], *(double *)&big_byte_array[0x18 * i - 0x20]); if ( gauntlet(v44) ) { v60 = i / 8; v61 = i % 8; v41 = (1 << (7 - i % 8)) ^ *((unsigned __int8 *)flag_shit + i / 8); *((_BYTE *)flag_shit + v60) ^= 1 << (7 - i % 8); ++v56; } } 4. The number of times that gauntlet returns true are constant every iteration 5. The original flag_shit variable is across every iteration (edited)
Avatar
Lior 🟣🐑 07/01/2023 1:39 AM
are is?
Avatar
IceCreamMan 07/01/2023 1:39 AM
typo sry
Avatar
Lior 🟣🐑 07/01/2023 1:40 AM
thanks for the summary
Avatar
Avatar
IceCreamMan
import IPython bit_arr = [0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0] original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9] for i in range(0,len(bit_arr)): idx = bit_arr[i] if (idx == 1): v63 = int(i / 8) original_flag[v63] ^= 1 << (7 - i % 8); print(original_flag) string = ''.join(chr(num) for num in original_flag) print(string) IPython.embed()
IceCreamMan 07/01/2023 1:40 AM
these are the values that are always generated, bit_arr is the number of times gauntlet returns true
Avatar
Avatar
IceCreamMan
import IPython bit_arr = [0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0] original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9] for i in range(0,len(bit_arr)): idx = bit_arr[i] if (idx == 1): v63 = int(i / 8) original_flag[v63] ^= 1 << (7 - i % 8); print(original_flag) string = ''.join(chr(num) for num in original_flag) print(string) IPython.embed()
Lior 🟣🐑 07/01/2023 1:41 AM
These are the values of the gaunlet?
01:41
(each iteration)
Avatar
IceCreamMan 07/01/2023 1:41 AM
the return value
Avatar
Lior 🟣🐑 07/01/2023 1:41 AM
if I understand you correctly
01:41
yup yup
Avatar
IceCreamMan 07/01/2023 1:41 AM
yeap correct
Avatar
Avatar
IceCreamMan
3. The most important parts are here: for ( i = 0; i < (int)val_368; ++i ) { v44 = calculate( *(_QWORD *)&big_byte_array[0x18 * i - 0x30],// these are arguments on the stack *(double *)&big_byte_array[0x18 * i - 0x28], *(double *)&big_byte_array[0x18 * i - 0x20]); if ( gauntlet(v44) ) { v60 = i / 8; v61 = i % 8; v41 = (1 << (7 - i % 8)) ^ *((unsigned __int8 *)flag_shit + i / 8); *((_BYTE *)flag_shit + v60) ^= 1 << (7 - i % 8); ++v56; } } 4. The number of times that gauntlet returns true are constant every iteration 5. The original flag_shit variable is across every iteration (edited)
Lior 🟣🐑 07/01/2023 1:43 AM
are v61, v41 and v56 used?
01:43
will open in IDA in abit
Avatar
IceCreamMan 07/01/2023 1:44 AM
the decompilation is ugly, originally it looks like this: for ( i = 0; i < (int)v62; ++i ) { v47 = calculate((unsigned int)&v54, (_DWORD)v43, i, v44, v45, v46, v73[3 * i], v73[3 * i + 1], v73[3 * i + 2]); if ( (unsigned __int8)gauntlet(v47) ) { v63 = i / 8; v64 = i % 8; LODWORD(v43) = 1 << (7 - i % 8); v44 = (unsigned int)v43 ^ *((unsigned __int8 *)v69 + i / 8); *((_BYTE *)v69 + v63) ^= 1 << (7 - i % 8); ++v59; } }
Avatar
Lior 🟣🐑 07/01/2023 1:44 AM
btw, do you think a VM is needed to safely run this
01:44
or can I run on my local machine
01:44
(haven't checked all of the binary yet)
Avatar
IceCreamMan 07/01/2023 1:44 AM
v44 is used in calculate
Avatar
safe don't worry
Avatar
IceCreamMan 07/01/2023 1:45 AM
double __fastcall calculate(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, double a7, double a8, double a9, double a10, double a11, double a12, double a13, double a14, unsigned int a15, double a16, double a17) { double v10; // [rsp+8h] [rbp-8h] v10 = 0.0; if ( a15 > 0x2F ) { if ( a15 == 94 ) v10 = powf64(a16, a17); } else if ( a15 >= 0x25 && a15 - 37 <= 0xA ) { __asm { jmp rax } } return v10; } But in calculate it just uses a15, a16, and a17 (edited)
Avatar
Lior 🟣🐑 07/01/2023 1:45 AM
I see
Avatar
Avatar
IceCreamMan
3. The most important parts are here: for ( i = 0; i < (int)val_368; ++i ) { v44 = calculate( *(_QWORD *)&big_byte_array[0x18 * i - 0x30],// these are arguments on the stack *(double *)&big_byte_array[0x18 * i - 0x28], *(double *)&big_byte_array[0x18 * i - 0x20]); if ( gauntlet(v44) ) { v60 = i / 8; v61 = i % 8; v41 = (1 << (7 - i % 8)) ^ *((unsigned __int8 *)flag_shit + i / 8); *((_BYTE *)flag_shit + v60) ^= 1 << (7 - i % 8); ++v56; } } 4. The number of times that gauntlet returns true are constant every iteration 5. The original flag_shit variable is across every iteration (edited)
IceCreamMan 07/01/2023 1:46 AM
so i dont think v44 was used... but i may miss some details
Avatar
Avatar
joezid
safe don't worry
IceCreamMan 07/01/2023 1:47 AM
haha the only idea i have seems to be brute forcing... and assume the number of flipped bits is a constant 119 (edited)
Avatar
Avatar
IceCreamMan
haha the only idea i have seems to be brute forcing... and assume the number of flipped bits is a constant 119 (edited)
Lior 🟣🐑 07/01/2023 1:47 AM
maybe doable given that the flag has printable characters? not likely tho (edited)
Avatar
Yes there is nothing else so probably we will have to do it in this way
Avatar
Lior 🟣🐑 07/01/2023 1:48 AM
nah not really
Avatar
i will work on it
Avatar
IceCreamMan 07/01/2023 1:48 AM
but there are quite a number of permuations..
01:49
uiuctf{Ahis is a fake flag. You are too fast!} uiuctf{Bhis is a fake flag. You are too fast!} uiuctf{Chis is a fake flag. You are too fast!} uiuctf{Dhis is a fake flag. You are too fast!} uiuctf{Ehis is a fake flag. You are too fast!} uiuctf{Fhis is a fake flag. You are too fast!} uiuctf{Ghis is a fake flag. You are too fast!} uiuctf{Hhis is a fake flag. You are too fast!} uiuctf{Ihis is a fake flag. You are too fast!} uiuctf{Jhis is a fake flag. You are too fast!} uiuctf{Khis is a fake flag. You are too fast!} uiuctf{Lhis is a fake flag. You are too fast!} uiuctf{Mhis is a fake flag. You are too fast!} uiuctf{Nhis is a fake flag. You are too fast!} uiuctf{Ohis is a fake flag. You are too fast!} uiuctf{phis is a fake flag. You are too fast!} uiuctf{qhis is a fake flag. You are too fast!} uiuctf{rhis is a fake flag. You are too fast!} Eg for the first char
Avatar
Lior 🟣🐑 07/01/2023 1:49 AM
lol they actually use alloca
01:49
there's the pwnable.kr alloca challenge
Avatar
Avatar
Lior 🟣🐑
lol they actually use alloca
IceCreamMan 07/01/2023 1:49 AM
haha it makes the decompilation ugly 😦
Avatar
Lior 🟣🐑 07/01/2023 1:52 AM
lol wtf
01:52
useless code?
01:52
ida being clown as per usual (edited)
Avatar
IceCreamMan 07/01/2023 1:53 AM
yeah ugly code ...
01:59
Hex-Rays microcode API plugin for breaking an obfuscating compiler - HexRaysDeob/AllocaFixer.cpp at master · RolfRolles/HexRaysDeob
01:59
@IceCreamMan
01:59
bypass for alloca obfuscation
Avatar
IceCreamMan 07/01/2023 2:00 AM
let me try, thanks!
Avatar
Lior 🟣🐑 07/01/2023 2:00 AM
wanna hop on VC and share screen?
02:00
@IceCreamMan
02:00
you dont have to talk or hear me
Avatar
IceCreamMan 07/01/2023 2:01 AM
ok
Avatar
Lior 🟣🐑 07/01/2023 2:01 AM
share screen
02:01
@IceCreamMan
02:02
@IceCreamMan are you loading the plugin?
Avatar
IceCreamMan 07/01/2023 2:02 AM
i have no idea what to try actually, i want to try the alloca fixer
02:02
lol i am finding out how to haha
02:02
nvr used a plugin before
Avatar
Lior 🟣🐑 07/01/2023 2:02 AM
you are only sharing a single screen
02:04
02:04
@IceCreamMan I think you simply need to set the environment variables
02:04
to point to your ida
02:05
I looked at different extensions that have docs
02:05
for instance this one
02:05
Hex-Rays Decompiler plugin for better code navigation - GitHub - REhints/HexRaysCodeXplorer: Hex-Rays Decompiler plugin for better code navigation
02:05
02:06
02:06
foind it
Avatar
IceCreamMan 07/01/2023 2:06 AM
HAHA how do it do it?
02:06
🤣
Avatar
Lior 🟣🐑 07/01/2023 2:06 AM
wait
02:06
@IceCreamMan
02:06
look at makefile.lnx
02:06
in our plugin's repo
02:06
they pasted instructins
02:06
set IDA_DIR and IDA_SDK
02:07
doing it right now as well
Avatar
IceCreamMan 07/01/2023 2:07 AM
use this makefile to build HexRaysDeob for Linux
02:07
you are building for linux?
Avatar
Lior 🟣🐑 07/01/2023 2:08 AM
no, but I think the method should be the same for windows
02:08
for me, IDA_SDK is at C:\Program Files\IDA 7.0\plugins\hexrays_sdk
02:08
for example
Avatar
IceCreamMan 07/01/2023 2:08 AM
oh they are alrd built i think
02:08
C:\Users\User\Desktop\HexRaysDeob-master\HexRaysDeob-master\bin\IDA72_32
02:09
but for 72 😦
Avatar
Lior 🟣🐑 07/01/2023 2:12 AM
wait what are you doing now @IceCreamMan
02:12
I wasnt looking
02:12
did you add the plugin?
Avatar
IceCreamMan 07/01/2023 2:12 AM
i didnt.. i think i have to compile that Windows Once you have a copy of the plug-in, installing the plug-in is as simple as copying the Python file into the plugins folder. For IDA 6.9, the default installation path can be found at: https://first-plugin-ida.readthedocs.io/en/latest/installing.html
02:13
i tot the bin folder was useful, there is compiled dll inside
Avatar
Lior 🟣🐑 07/01/2023 2:14 AM
I am not copying that dll lmao
02:14
prefer to compile myself
Avatar
IceCreamMan 07/01/2023 2:14 AM
🤣 maybe i will live without that hahaha
Avatar
Lior 🟣🐑 07/01/2023 2:14 AM
fuck vs
02:14
Avatar
IceCreamMan 07/01/2023 2:14 AM
🤣
02:15
i am jsut relooking if i missed out anything.. which i dont think i did
02:15
haha if not code the brute force
Avatar
IceCreamMan 07/01/2023 2:23 AM
i wonder how this byte array came out... for ( i = 0; i < (int)val_368; ++i ) { v44 = calculate( *(_QWORD *)&big_byte_array[0x18 * i - 0x30],// these are arguments on the stack *(double *)&big_byte_array[0x18 * i - 0x28], *(double *)&big_byte_array[0x18 * i - 0x20]);
02:23
00:0000│ rsp 0x7fffffffaf50 ◂— 0x25 /* '%' */ 01:0008│ 0x7fffffffaf58 ◂— 0x4073a3c584d895d0 02:0010│ 0x7fffffffaf60 ◂— 0xc0757ccd8b26163a
02:29
.rodata:00000000004B8240 asc_4B8240 db '%',0 ; DATA XREF: main+A0↑o .rodata:00000000004B8242 align 8 .rodata:00000000004B8248 db 0D0h .rodata:00000000004B8249 db 95h .rodata:00000000004B824A db 0D8h .rodata:00000000004B824B db 84h .rodata:00000000004B824C db 0C5h .rodata:00000000004B824D db 0A3h .rodata:00000000004B824E db 73h ; s .rodata:00000000004B824F db 40h ; @ .rodata:00000000004B8250 db 3Ah ; : .rodata:00000000004B8251 db 16h .rodata:00000000004B8252 db 26h ; & .rodata:00000000004B8253 db 8Bh Oh it came from here
Avatar
Lior 🟣🐑 07/01/2023 2:30 AM
still working on building the plugin lmao
02:30
almost there
Avatar
IceCreamMan 07/01/2023 2:30 AM
okay lol
Avatar
Avatar
IceCreamMan
.rodata:00000000004B8240 asc_4B8240 db '%',0 ; DATA XREF: main+A0↑o .rodata:00000000004B8242 align 8 .rodata:00000000004B8248 db 0D0h .rodata:00000000004B8249 db 95h .rodata:00000000004B824A db 0D8h .rodata:00000000004B824B db 84h .rodata:00000000004B824C db 0C5h .rodata:00000000004B824D db 0A3h .rodata:00000000004B824E db 73h ; s .rodata:00000000004B824F db 40h ; @ .rodata:00000000004B8250 db 3Ah ; : .rodata:00000000004B8251 db 16h .rodata:00000000004B8252 db 26h ; & .rodata:00000000004B8253 db 8Bh Oh it came from here
IceCreamMan 07/01/2023 2:32 AM
this is used here... v3 = (__int64 *)"%"; j_memcpy(v73, "%", sizeof(v73)); ---> memcpy the big array v74[0] = 0x10EEB90001E1C34BLL; v74[1] = 0xCB382178A4F04BEELL; v74[2] = 0xE84683CE6B212AEALL; v74[3] = 0xA0F5CF092C8CA741LL; v74[4] = 0x20A92860082772A1LL; All the way at the start
Avatar
@chenx3n wants to collaborate 🤝
Avatar
Lior 🟣🐑 07/01/2023 2:34 AM
I have a feeling you will solve the challenge before I finish setting up the plugin
02:34
lmao
Avatar
IceCreamMan 07/01/2023 2:34 AM
i still have no new idea lol
Avatar
Avatar
Lior 🟣🐑
I have a feeling you will solve the challenge before I finish setting up the plugin
IceCreamMan 07/01/2023 2:35 AM
haha making ida nice is important
Avatar
Lior 🟣🐑 07/01/2023 2:38 AM
ok I found the issue @IceCreamMan
02:38
In the VS solution
02:38
in additional depencencies
02:38
he put
02:38
c:\work\src\idasdk72\lib\x64_win_vc_64\ida.lib
02:39
which is a path on his local computer clownglasses
Avatar
IceCreamMan 07/01/2023 2:40 AM
🤣
Avatar
Lior 🟣🐑 07/01/2023 2:41 AM
fuck
02:41
02:41
there were major api changes
02:42
between ida 7.0 and ida 7.2
02:42
there is no lib file at all
02:49
fuck I am missing files
Avatar
IceCreamMan 07/01/2023 3:04 AM
🤣
Avatar
Lior 🟣🐑 07/01/2023 3:11 AM
oh. no.
03:12
nothing like sketchy chinese websites
Avatar
@Iyed wants to collaborate 🤝
Avatar
Lior 🟣🐑 07/01/2023 3:18 AM
@Iyed @chenx3n do you have ida installed
03:18
with version 7.0-7.3
03:18
@IceCreamMan
03:18
if so
Avatar
I have 7.4
Avatar
Lior 🟣🐑 07/01/2023 3:18 AM
fuck
03:18
ok quick check
03:18
maybe we will solve the challenge from your computer
03:18
go do your ida folder
03:19
then go to plugins
03:19
then go to hexrays_sdk / idasdk / however its called
03:19
@Iyed send a screenshot of the files you see
03:19
also,do you have somewhere in your ida folder a file called "ida.lib"?
03:19
we NEED this
Avatar
ok I have also 7.0.1 (edited)
Avatar
Lior 🟣🐑 07/01/2023 3:19 AM
otherwise I need to translate a c++ written ida pro plugin to python
03:19
awesome!!!! use 7.0.1
03:19
can you voice chat?
03:20
you can save us
Avatar
Avatar
Lior 🟣🐑
@Iyed send a screenshot of the files you see
Lior 🟣🐑 07/01/2023 3:20 AM
do this please
Avatar
ok just a minute
03:20
I just woke up
Avatar
Lior 🟣🐑 07/01/2023 3:20 AM
yay
03:20
ah ok
03:22
@Iyed the most optimal version would be 7.1 or 7.2
03:23
we can try to translate
03:23
this
03:23
to python
03:27
lol gpt 4 might have actually done something useful
Avatar
yeah I'm thinking of that 😂
Avatar
Lior 🟣🐑 07/01/2023 3:28 AM
Copy code import idaapi import idautils import idc # Plugin skeleton class alloca_deobfuscator_t(idaapi.plugin_t): flags = 0 comment = "Deobfuscate alloca() obfuscation" help = "No help" wanted_name = "Alloca Deobfuscator" wanted_hotkey = "Ctrl-Shift-A" def init(self): self.hotkey_ctx = ida_kernwin.add_hotkey(self.wanted_hotkey, self.run) if self.hotkey_ctx is None: return idaapi.PLUGIN_SKIP else: return idaapi.PLUGIN_KEEP def term(self): ida_kernwin.del_hotkey(self.hotkey_ctx) def run(self, arg): # Get a list of all functions in the binary for func_ea in idautils.Functions(): f = ida_funcs.get_func(func_ea) if not f: continue func_name = ida_funcs.get_func_name(func_ea) # Iterate over all instructions in the function for head in idautils.Heads(f.start_ea, f.end_ea): if ida_ua.is_call_insn(head): # Get callee address if it's a direct call callee = idc.get_operand_value(head, 0) callee_name = ida_name.get_name(callee) if callee_name == "alloca": # Check if alloca argument is a constant if idc.get_operand_type(head, 1) == idc.o_imm: alloca_size = idc.get_operand_value(head, 1) # Modify stack frame size f.frame_regs.sp = f.frame_regs.sp - alloca_size ida_funcs.set_func_frame(f) # Force re-analysis of the function ida_auto.auto_wait() ida_auto.plan_and_wait(f.start_ea, f.end_ea) print(f"Deobfuscated alloca call in {func_name}") print("Finished deobfuscation.") def run(self, arg): self.deobfuscate_alloca() def PLUGIN_ENTRY(): return alloca_deobfuscator_t()
03:28
I wonder if this actually works
03:28
(I of course instructed it to change some stuff)
Avatar
Avatar
Lior 🟣🐑
@Iyed @chenx3n do you have ida installed
nope :/
Avatar
Lior 🟣🐑 07/01/2023 3:54 AM
@Iyed
03:55
can you hear me
03:57
import idaapi import idautils import idc # Plugin skeleton class alloca_deobfuscator_t(idaapi.plugin_t): flags = 0 comment = "Deobfuscate alloca() obfuscation" help = "No help" wanted_name = "Alloca Deobfuscator" wanted_hotkey = "Ctrl-Shift-A" def init(self): self.hotkey_ctx = ida_kernwin.add_hotkey(self.wanted_hotkey, self.run) if self.hotkey_ctx is None: return idaapi.PLUGIN_SKIP else: return idaapi.PLUGIN_KEEP def term(self): ida_kernwin.del_hotkey(self.hotkey_ctx) def run(self, arg): # Get a list of all functions in the binary for func_ea in idautils.Functions(): f = ida_funcs.get_func(func_ea) if not f: continue func_name = ida_funcs.get_func_name(func_ea) # Iterate over all instructions in the function for head in idautils.Heads(f.start_ea, f.end_ea): if ida_ua.is_call_insn(head): # Get callee address if it's a direct call callee = idc.get_operand_value(head, 0) callee_name = ida_name.get_name(callee) if callee_name == "alloca": # Check if alloca argument is a constant if idc.get_operand_type(head, 1) == idc.o_imm: alloca_size = idc.get_operand_value(head, 1) # Modify stack frame size f.frame_regs.sp = f.frame_regs.sp - alloca_size ida_funcs.set_func_frame(f) # Force re-analysis of the function ida_auto.auto_wait() ida_auto.plan_and_wait(f.start_ea, f.end_ea) print(f"Deobfuscated alloca call in {func_name}") print("Finished deobfuscation.") def run(self, arg): self.deobfuscate_alloca() def PLUGIN_ENTRY(): return alloca_deobfuscator_t()
04:00
c++ for (auto g : af.m_FixupLocations) { // Set the stack point on the *subsequent* EA (thanks, Hex-Rays!) ea_t eaNext = get_item_end(g.first); msg("[I] Adding auto stack point at %a: %d\n", eaNext, -g.second); // ... fix its stack pointer differential if (!add_auto_stkpnt(f, eaNext, -g.second)) { msg("[E] Couldn't change stack delta to %d at %a\n", -g.second, g.first); // YOLO add_user_stkpnt(eaNext, -g.second); } }
Avatar
IceCreamMan 07/01/2023 4:36 AM
does the secret operation thing mean anything?
04:36
If you enter the correct secret operation, I might decrypt the flag for you! ^-^
Avatar
IceCreamMan 07/01/2023 5:13 AM
looks like there is some guessing... maybe lets try to assume there is identical number of flipped bits in each set of 8...
Avatar
I checked all the functions even searched for any other encrypted buffer that can be decrypted using the same bit flipping order but nothing 🥲
Avatar
Avatar
IceCreamMan
looks like there is some guessing... maybe lets try to assume there is identical number of flipped bits in each set of 8...
IceCreamMan 07/01/2023 5:15 AM
i feel dumb tho, does anyone have better ideas?
05:15
🤣
Avatar
Lior 🟣🐑 07/01/2023 5:15 AM
@IceCreamMan I am able to write python plugins now
05:15
I made ida plugin loader actually work
Avatar
Avatar
joezid
I checked all the functions even searched for any other encrypted buffer that can be decrypted using the same bit flipping order but nothing 🥲
IceCreamMan 07/01/2023 5:15 AM
bad challenge...
05:15
argh
Avatar
Lior 🟣🐑 07/01/2023 5:15 AM
I am converting the plugin now to python
Avatar
Avatar
joezid
I checked all the functions even searched for any other encrypted buffer that can be decrypted using the same bit flipping order but nothing 🥲
i think there is no hidden logic
Avatar
I mean it's always running these instructions no matter what I input
Avatar
IceCreamMan 07/01/2023 5:15 AM
yea
Avatar
just need guessing
Avatar
yes guessing
Avatar
IceCreamMan 07/01/2023 5:16 AM
hais
Avatar
Avatar
Lior 🟣🐑
@IceCreamMan I am able to write python plugins now
IceCreamMan 07/01/2023 5:16 AM
haha at least you are learning something LOL
05:16
i feel stupid 🤣
Avatar
Avatar
sahuang
i think there is no hidden logic
Exactly but I thought maybe as the challenge mentioned a secret operation we will find something 😂
Avatar
secret operation is useless
Avatar
Lior 🟣🐑 07/01/2023 5:30 AM
ok I give up on fixing allocas
05:30
lol
Avatar
IceCreamMan 07/01/2023 5:41 AM
Sheet1 Operation in hex,Gaunlet returned results,Flag character 0,0x0000000000000025,0,U 1,0x000000000000002d,0 2,0x0000000000000025,1 3,0x000000000000002f,1 4,0x0000000000000025,1 5,0x000000000000002f,1 6,0x0000000000000025,1 7,0x000000000000002d,0 8,0x000000000000005e,1,I 9,0x000000000000002a,...
05:42
i dumped out the operation and the flag char... if anyone can give a good guess lol
Avatar
uiuctf{ is fixed
Avatar
IceCreamMan 07/01/2023 5:43 AM
i dont see any good pattern 😦
Avatar
Lior 🟣🐑 07/01/2023 5:43 AM
do you have all characters?
05:43
(without xoring anything)
Avatar
IceCreamMan 07/01/2023 5:43 AM
oh the original flag
05:43
original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9]
Avatar
Lior 🟣🐑 07/01/2023 5:43 AM
no like
05:44
I mean
05:44
setting orignal_flag
05:44
to be all zeros
05:44
wait that wont work lol
05:44
oops
Avatar
Avatar
IceCreamMan
original_flag = [0x4b, 0xc3, 0xe1, 0x01, 0x00, 0xb9, 0xee, 0x10, 0xee, 0x4b, 0xf0, 0xa4, 0x78, 0x21, 0x38, 0xcb, 0xea, 0x2a, 0x21, 0x6b, 0xce, 0x83, 0x46, 0xe8, 0x41, 0xa7, 0x8c, 0x2c, 0x09, 0xcf, 0xf5, 0xa0, 0xa1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xa9, 0x20, 0x66, 0xb3, 0xab, 0x35, 0xa4, 0xe9]
IceCreamMan 07/01/2023 5:44 AM
all zeros should be doing nothing and returns this
05:44
i think
Avatar
Lior 🟣🐑 07/01/2023 5:44 AM
@IceCreamMan can you send the stream of bits gaunlet returns in a more comfortable format
05:44
(and not an excel sheet)
05:45
(assuming you have it)
Avatar
00111110101010101001010001100010011101001101111110010101010001001000011000100010100000111000010000010001010100100001100010101010110010100100110001000000000000001010101110100011001000001000010000100000110000001010001000001100010100001010000010000000100000001100000000000000010000100010100000010100010001111100011000000000000000001101001011011000010000011000010110010100
Avatar
IceCreamMan 07/01/2023 5:45 AM
need some luck LOL
Avatar
flag should be meaningful
05:46
with _ separated
05:46
so i guess all space are flipped to _
Avatar
uiuctf{This_is_a_fake_flag._You_are_too_fast!} so maybe somehting like this ? (edited)
Avatar
idk, maybe not, 🤣
Avatar
uiuctf{This_is_a_real_flag._You_are_too_good!}msfrog
05:49
bad guess 😂
😂 1
Avatar
IceCreamMan 07/01/2023 5:50 AM
hahahah
Avatar
So any ideas ?
Avatar
Avatar
IceCreamMan
looks like there is some guessing... maybe lets try to assume there is identical number of flipped bits in each set of 8...
IceCreamMan 07/01/2023 5:51 AM
i am generating some permutations now with this assumption lol
05:51
still seems like a bad idea HAHA
Avatar
garunet will this change?
05:51
or we fix 0/1 of this (edited)
Avatar
Lior 🟣🐑 07/01/2023 5:53 AM
ok this chal is way too guessy (edited)
05:53
gotta go study, glhf
05:58
these are operations it's executing to decrypt fake flag
Avatar
IceCreamMan 07/01/2023 6:15 AM
T: p@XTRQ 8421 h: >&*,/^FJLOvz|bdghkm i: {coijS_YZGABMNH s: 8421@XTRQhdba|zyvus : d4, &% i: (0<:9HP\ZY`ljitrq~}{ s: QIEC@yuspmkhgdb=;8742/,*& : Xhp|zy ,*)421>=; a: syzgabmnhWQR]^XEF@L Able to make any guesses? lol
06:16
The first 4 chars still seems like This 💀
Avatar
this is all possible 2**8 flips?
Avatar
Avatar
Iyed
Click to see attachment 🖼️
Lior 🟣🐑 07/01/2023 6:56 AM
oh shit
06:56
the xors look like printable ascii values!!!! (edited)
06:58
nah actually there's 15 there (edited)
Avatar
Avatar
sahuang
this is all possible 2**8 flips?
IceCreamMan 07/01/2023 6:58 AM
according to the number of 1s in the set of 8 (edited)
Avatar
I'm afraid the flag is gonna be extracted from those doubles
07:14
the value he is doing comparaison with in the while loop
07:15
is UIUC I guess
07:15
if you take 2 digits and convert to ascii
Avatar
IceCreamMan 07/01/2023 7:16 AM
each letter is 8 operations, how do you see the ascii?
Avatar
Avatar
IceCreamMan
1. The decompiled code just checks if the sum of an operation is 8573.8567 2. however the user inputs does not seem to be used at all
I'm not on my computer hut here
07:17
85 73 85 67
07:23
The operation values are the same, but you may need to check some of the functions used to compute the operation... they might have issues
07:23
what an admin said
Avatar
IceCreamMan 07/01/2023 7:25 AM
hmm
07:25
thats a good hint
Avatar
double __fastcall calculate( __int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, double a7, double a8, double a9, double a10, double a11, double a12, double a13, double a14, unsigned int a15, double a16, double a17) { double v10; // [rsp+8h] [rbp-8h] v10 = 0.0; if ( a15 > '/' ) { if ( a15 == '^' ) return powf64(a16, a17); } else if ( a15 >= '%' ) { switch ( a15 ) { case '%': v10 = fmodf64(a16, a17); break; case '*': v10 = a17 * a16; break; case '+': v10 = a17 + a16; break; case '-': v10 = a16 - a17; break; case '/': v10 = a16 / a17; break; default: return v10; } } return v10; }
07:26
so where can be the problem
07:26
in powf64 or fmodf64 ?
Avatar
Functions resulting in wrong values, correct
07:29
maybe the pow
Avatar
IceCreamMan 07/01/2023 7:29 AM
maybe overflow etc
Avatar
Avatar
Iyed
Click to see attachment 🖼️
IceCreamMan 07/01/2023 7:30 AM
but maybe related to this rather than user input
Avatar
yes i think this is the problem
07:31
we can recalculate all the equations and try to decrypt the flag using our code
Avatar
Avatar
Iyed
Click to see attachment 🖼️
so we need to recalculate gournet? @IceCreamMan what do you think? to get correct flipped bits
07:56
its a "coincidence" that first 7*8 calculations give correct gaunlet though
Avatar
#!/usr/bin/python3 import struct from pwn import * from decimal import Decimal with open("./calc", "rb") as f: biny = f.read() f.close() enc = [0x4B, 0xC3, 0xE1, 0x01, 0x00, 0xB9, 0xEE, 0x10, 0xEE, 0x4B, 0xF0, 0xA4, 0x78, 0x21, 0x38, 0xCB, 0xEA, 0x2A, 0x21, 0x6B, 0xCE, 0x83, 0x46, 0xE8, 0x41, 0xA7, 0x8C, 0x2C, 0x09, 0xCF, 0xF5, 0xA0, 0xA1, 0x72, 0x27, 0x08, 0x60, 0x28, 0xA9, 0x20, 0x66, 0xB3, 0xAB, 0x35, 0xA4, 0xE9] c = 0xb8240 ops = biny[c:c + 0x2280] v16 = 0 j = 0 for i in range(0, len(ops), 24): eq = ops[i:i+24] o = chr(u64(eq[:8])) x = str(Decimal.from_float(struct.unpack('<d', eq[8:16])[0])) y = str(Decimal.from_float(struct.unpack('<d', eq[16:24])[0])) if (o == "%"): e = x + o + y elif (o == "*"): e = y + o + x elif (o == "+"): e = y + o + x elif (o == "-"): e = x + o + y elif (o == "/"): e = x + o + y elif (o == "^"): e = f"pow({x}, {y})" res = eval(e) if (("j" in str(res)) or (res < 0)): v20 = j / 8; v21 = j % 8; enc[int(j / 8)] ^= 1 << (7 - j % 8); v16 += 1 j += 1 print(v16) print(b"".join([bytearray([i]) for i in enc]))
08:03
It's getting wrong stuff
08:04
but I guess if we just increase precision or something
Avatar
IceCreamMan 07/01/2023 8:05 AM
does it match the first 6 chars UIUCTF{?
Avatar
IceCreamMan 07/01/2023 8:05 AM
Expression: 314.23572239497753 % -343.80018153073945 = Result: -29.564459135761922 Yeah the first char is negative
Avatar
its lower cased flag format
08:08
00111110 shouldnt change
Avatar
IceCreamMan 07/01/2023 8:37 AM
got it
Avatar
how?
Avatar
Avatar
IceCreamMan
used /ctf solve
✅ Challenge solved.
Avatar
Good job
08:38
How did you solve it?
Avatar
IceCreamMan 07/01/2023 8:38 AM
I used javascript to do the IEEE64 evaluation
15.98 KB
08:39
final_res = [] function isNegative(num) { if (Math.sign(num) === -1) { return true; } return false; } for (let i = 0; i < arr.length; i++) { result = eval(arr[i]); console.log(result) if (isNegative(result)){ final_res.push(1); } else if (Object.is(result, -0)){ final_res.push(1); } else{ final_res.push(0); } }
08:39
js returns a % -b as positive? (edited)
Avatar
IceCreamMan 07/01/2023 8:41 AM
its funky (edited)
08:41
08:41
there are lots of -0
08:42
Avatar
IceCreamMan 07/01/2023 8:42 AM
but if you do Math.sign(-0), it doesnt show negative lol
Avatar
interesting
Avatar
Avatar
IceCreamMan
final_res = [] function isNegative(num) { if (Math.sign(num) === -1) { return true; } return false; } for (let i = 0; i < arr.length; i++) { result = eval(arr[i]); console.log(result) if (isNegative(result)){ final_res.push(1); } else if (Object.is(result, -0)){ final_res.push(1); } else{ final_res.push(0); } }
IceCreamMan 07/01/2023 8:42 AM
thats why i hardcoded it here using the Object.is
08:43
damn finally done
08:43
that admin hint helps a lot, thanks @Iyed
Avatar
yeah 💀
08:43
guessy
Avatar
Avatar
sahuang
guessy
IceCreamMan 07/01/2023 8:47 AM
just got misled the wrong way
Avatar
yeah
08:47
true
Avatar
Avatar
sahuang
guessy
he could've made a better description
Exported 452 message(s)